/*
 * Package il.ac.biu.cs.grossmm.test.fooFormat
 * File WatcherRulesDoc.java
 * 
 * This is a part of presence service framework API. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package il.ac.biu.cs.grossmm.foo.format;

import java.util.HashSet;
import java.util.Set;

public class WatcherRulesDoc {
	private static final char DELIM = '|';

	private static final char DELIM2 = ';';
	
	public static final String CONTENT_TYPE = "foo.WatcherRulesDoc";

	Set<PersonalRule> personalRules = new HashSet<PersonalRule>();

	Set<ServiceRule> serviceRules = new HashSet<ServiceRule>();

	
	int p;

	public static class PersonalRule {
		public String sphere;

		public String watcher;

		// action
		public boolean allowAccess; // false => deny

		// transformations, valid only if allowAccess == true
		public boolean showActivities;

		public boolean showLocation;

		public boolean showMood;

		public boolean showSphere;

		/**
		 * rule which totally blocks any access by default
		 * 
		 */
		public PersonalRule()
		{
		}

		/**
		 * @param sphere
		 * @param watcher
		 * @param allowAccess
		 * @param showActivities
		 * @param showLocation
		 * @param showMood
		 * @param showSphere
		 */
		public PersonalRule(String sphere, String watcher,
			boolean showActivities, boolean showLocation, boolean showMood,
			boolean showSphere)
		{
			super();
			this.sphere = sphere;
			this.watcher = watcher;
			this.allowAccess = true;
			this.showActivities = showActivities;
			this.showLocation = showLocation;
			this.showMood = showMood;
			this.showSphere = showSphere;
		}

		/**
		 * 
		 * @param sphere
		 * @param watcher
		 * @param fullAccess
		 */
		public PersonalRule(String sphere, String watcher, boolean fullAccess)
		{
			super();
			
			this.sphere = sphere;
			this.watcher = watcher;
			
			this.allowAccess = fullAccess;
			this.showActivities = fullAccess;
			this.showLocation = fullAccess;
			this.showMood = fullAccess;
			this.showSphere = fullAccess;
		}
	}

	public static class ServiceRule {
		// condition
		public String sphere; // null = any sphere

		public String watcher; // null = everyone + anonymous

		public String tupleClass;

		// transformations
		public boolean showPresence; // false => polite block. no deny action

		public boolean showCapabilities;

		public boolean showClass;

		/**
		 * polite blocks all tuples (i.e. shows status as offline, no class, no
		 * capabilities)
		 * 
		 */
		public ServiceRule()
		{
		}

		/**
		 * @param sphere
		 * @param watcher
		 * @param tupleClass
		 * @param showPresence
		 * @param showCapabilities
		 * @param showClass
		 */
		public ServiceRule(String sphere, String watcher, String tupleClass,
			boolean showPresence, boolean showCapabilities, boolean showClass)
		{
			super();
			this.sphere = sphere;
			this.watcher = watcher;
			this.tupleClass = tupleClass;
			this.showPresence = showPresence;
			this.showCapabilities = showCapabilities;
			this.showClass = showClass;
		}

	}

	public WatcherRulesDoc(CharSequence serialized)
	{

		while (serialized.charAt(p) != DELIM2) {
			PersonalRule pr = new PersonalRule();
			pr.sphere = nextString(serialized);
			pr.watcher = nextString(serialized);

			int b = serialized.charAt(p++) - '0';

			pr.allowAccess = b != 0;

			if (pr.allowAccess) {
				pr.showActivities = (b & 1) != 0;
				pr.showLocation = (b & (1 << 1)) != 0;
				pr.showMood = (b & (1 << 2)) != 0;
				pr.showSphere = (b & (1 << 3)) != 0;
			}

			personalRules.add(pr);
		}
		
		p++;

		while (serialized.charAt(p) != DELIM2) {
			ServiceRule tr = new ServiceRule();

			tr.sphere = nextString(serialized);
			tr.watcher = nextString(serialized);
			tr.tupleClass = nextString(serialized);

			int b = serialized.charAt(p++) - '0';

			tr.showPresence = (b & 1) != 0;
			tr.showCapabilities = (b & (1 << 1)) != 0;
			tr.showClass = (b & (1 << 2)) != 0;
			
			serviceRules.add(tr);
		}
	}
	
	
	public WatcherRulesDoc()
	{
		// TODO Auto-generated constructor stub
	}


	public PersonalRule newPersonalRules()
	{
		PersonalRule pr = new PersonalRule();
		personalRules.add(pr);
		return pr;
	}

	public ServiceRule newTupleRules()
	{
		ServiceRule tr = new ServiceRule();
		serviceRules.add(tr);
		return tr;
	}

	public void addPersonalRules(String sphere, String watcher,
		boolean showActivities, boolean showLocation, boolean showMood,
		boolean showSphere)
	{
		personalRules.add(new PersonalRule(sphere, watcher, showActivities,
			showLocation, showMood, showSphere));
	}

	public void addPersonalRules(String sphere, String watcher,
		boolean fullAccess)
	{
		personalRules.add(new PersonalRule(sphere, watcher, fullAccess));
	}

	public void addServiceRules(String sphere, String watcher, String tupleClass,
		boolean showPresence, boolean showCapabilities, boolean showClass)
	{
		serviceRules.add(new ServiceRule(sphere, watcher, tupleClass, showPresence,
			showCapabilities, showClass));
	}

	public String serialize()
	{
		return serialize(null).toString();
	}

	public StringBuffer serialize(StringBuffer sb)
	{
		if (sb == null)
			sb = new StringBuffer(20);

		for (PersonalRule pr : personalRules) {

			write(sb, pr.sphere);
			write(sb, pr.watcher);
			int b;

			if (pr.allowAccess) {
				b = pr.showActivities ? 1 : 0;
				b |= pr.showLocation ? 1 << 1 : 0;
				b |= pr.showMood ? 1 << 2 : 0;
				b |= pr.showSphere ? 1 << 3 : 0;
				b |= 1 << 4;
			} else
				b = 0;

			sb.append((char) ('0' + b));
		}

		sb.append(DELIM2);

		for (ServiceRule tr : serviceRules) {

			write(sb, tr.sphere);
			write(sb, tr.watcher);
			write(sb, tr.tupleClass);

			int b = tr.showPresence ? 1 : 0;
			b |= tr.showCapabilities ? 1 << 1 : 0;
			b |= tr.showClass ? 1 << 2 : 0;
			sb.append((char) ('0' + b));
		}

		sb.append(DELIM2);

		return sb;
	}
	
	@Override
	public String toString()
	{
		StringBuffer sb = new StringBuffer('\n');
		for( PersonalRule pr : personalRules ) {
			sb.append("Personal( ");
			
			if( pr.sphere != null )
				sb.append("Sphere=").append(pr.sphere).append(' ');
			
			if( pr.watcher != null )
				sb.append("Watcher=").append(pr.watcher).append(' ');
			
			if(! pr.allowAccess )
				sb.append("forbidden ");
						
			if( pr.showActivities )
				sb.append("activities ");
			
			if( pr.showLocation)
				sb.append("location ");
			
			if( pr.showMood)
				sb.append("mood ");
			
			if( pr.showSphere)
				sb.append("sphere ");
			
			sb.append(")\n");
		}
		
		for( ServiceRule tr : serviceRules ) {
			sb.append("Service( ");
			
			if( tr.sphere != null )
				sb.append("Sphere=").append(tr.sphere).append(' ');
			
			if( tr.watcher != null )
				sb.append("Watcher=").append(tr.watcher).append(' ');
			
			if( tr.tupleClass != null )
				sb.append("Class=").append(tr.tupleClass).append(' ');
			
			if( tr.showCapabilities)
				sb.append("capabilities ");
			
			if( tr.showClass)
				sb.append("class ");
			
			if( tr.showPresence)
				sb.append("presence ");
			
			sb.append(")\n");
		}
		
		return sb.substring(0, sb.length()-1);
	}

	/**
	 * @param serialized
	 * @param j
	 * @return
	 */
	private String nextString(CharSequence serialized)
	{
		int p0 = p;
		while (true) {
			char c = serialized.charAt(p++);
			if( c == DELIM || c == DELIM2 )
				break;
		}

		if (p - p0 == 1)
			return null;

		return serialized.subSequence(p0, p-1).toString();
	}

	private static void write(StringBuffer sb, String str)
	{
		if (str != null)
			sb.append(str);

		sb.append(DELIM);
	}

	public static void main(String[] args)
	{
		WatcherRulesDoc doc = new WatcherRulesDoc();
		
		doc.addPersonalRules("kitchen", "bob", false);
		doc.addPersonalRules("kitchen", "jorge", true);
		doc.addPersonalRules("room", "bob", false, false, true, false);
		
		doc.addServiceRules("room", "jorge", "phones", true, true, false);
		
		
		System.out.println(doc.toString());
		System.out.println("---");
		
		String ser = doc.serialize();
		System.out.println(ser);		
		
		System.out.println("---");
		
		doc = new WatcherRulesDoc(ser);
		
		System.out.println(doc.toString());
	}


	/**
	 * @return the personalRules
	 */
	public Set<PersonalRule> getPersonalRules()
	{
		return personalRules;
	}


	/**
	 * @return the serviceRules
	 */
	public Set<ServiceRule> getServiceRules()
	{
		return serviceRules;
	}
}
